package com.example;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.Version;

import java.io.Writer;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

public class TemplateUtil {
    public static void generateJavaFile() throws Exception {
        // Load JSON configuration
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(TemplateUtil.class.getClassLoader().getResourceAsStream("config/mapping.json"));

        // Configure FreeMarker
        Configuration cfg = new Configuration(new Version("2.3.31"));
        cfg.setClassForTemplateLoading(TemplateUtil.class, "/templates");
        Template template = cfg.getTemplate("CopyPropertiesTemplate.ftl");

        // Prepare data model
        Map<String, Object> dataModel = new HashMap<>();
        List<TemplateEntity> dataList = objectMapper.convertValue(rootNode, new TypeReference<List<TemplateEntity>>() {
        });
        List<TemplateEntity2> mappings = new ArrayList<>();
        Set<String> classImportSet = new TreeSet<>();
        for (TemplateEntity templateEntity : dataList) {
            String description = templateEntity.getDescription();
            String version = templateEntity.getVersion();
            TemplateEntityDataItem data = templateEntity.getData();
            String classDescription = data.getClassDescription();
            List<String> classData = data.getClassData();
            List<TemplateEntityFieldDataItem> fieldData = data.getFieldData();
            for (int sourceIndex = 0; sourceIndex < classData.size(); sourceIndex++) {
                for (int targetIndex = 0; targetIndex < classData.size(); targetIndex++) {
                    if (sourceIndex == targetIndex) {
                        continue;
                    }
                    String sourceClass = classData.get(sourceIndex);
                    String sourceClassName = sourceClass.substring(sourceClass.lastIndexOf(".") + 1);
                    String targetClass = classData.get(targetIndex);
                    String targetClassName = targetClass.substring(targetClass.lastIndexOf(".") + 1);
                    TemplateEntity2 mapping = new TemplateEntity2();
                    mapping.setDescription(description);
                    mapping.setClassDescription(classDescription);
                    mapping.setVersion(version);
                    mapping.setSourceClass(sourceClass);
                    mapping.setSourceClassName(sourceClassName);
                    mapping.setTargetClass(targetClass);
                    mapping.setTargetClassName(targetClassName);
                    List<TemplateEntityFiledsItem> fields = new ArrayList<>();
                    for (int i = 0; i < fieldData.size(); i++) {
                        TemplateEntityFieldDataItem fieldDataItem = fieldData.get(i);
                        String fieldDescription = fieldDataItem.getFieldDescription();
                        List<String> fieldMapping = fieldDataItem.getFieldMapping();
                        String sourceField = fieldMapping.get(sourceIndex);
                        String targetField = fieldMapping.get(targetIndex);
                        TemplateEntityFiledsItem templateEntityFiledsItem = new TemplateEntityFiledsItem();
                        templateEntityFiledsItem.setFieldDescription(fieldDescription);
                        templateEntityFiledsItem.setSourceField(sourceFieldTypeCast(sourceField, targetField, sourceClass, targetClass, classImportSet));
                        templateEntityFiledsItem.setTargetField(targetField);
                        fields.add(templateEntityFiledsItem);
                    }
                    mapping.setFields(fields);
                    mappings.add(mapping);
                }
                String clazz = classData.get(sourceIndex);
                classImportSet.add(clazz);
            }
        }
        dataModel.put("mappings", mappings);
        dataModel.put("classImportSet", classImportSet);

        // Process template and write to file
        String filePath = "src/main/java/com/example/generated/PropertyCopier.java";
        Path directoryPath = Paths.get(filePath).getParent();
        if (directoryPath != null && !Files.exists(directoryPath)) {
            Files.createDirectories(directoryPath); // 创建多级目录
        }
//        cancelReadOnly(filePath);//不设置只读了，以免影响删除和文件替换给使用者带来困扰，禁止修改靠使用者自觉吧
        try (Writer out = Files.newBufferedWriter(Paths.get(filePath), StandardCharsets.UTF_8)) {
            template.process(dataModel, out);
        }
//        makeReadOnly(filePath);//不设置只读了，以免影响删除和文件替换给使用者带来困扰，禁止修改靠使用者自觉吧
    }

    private static String sourceFieldTypeCast(String sourceFieldStr, String targetFieldStr, String sourceClassStr, String targetClassStr, Set<String> classImportSet) throws ClassNotFoundException, NoSuchFieldException {
        Class<?> sourceClass = Class.forName(sourceClassStr);
        Class<?> targetClass = Class.forName(targetClassStr);
        Field sourceField = sourceClass.getDeclaredField(sourceFieldStr);
        sourceField.setAccessible(true);
        Field targetField = targetClass.getDeclaredField(targetFieldStr);
        targetField.setAccessible(true);
        String sourceFieldClassStr = sourceField.getType().getName();
        String targetFieldClassStr = targetField.getType().getName();

        classImportSet.add(sourceFieldClassStr);
        classImportSet.add(targetFieldClassStr);

        return getterAndcast(sourceFieldStr, sourceFieldClassStr, targetFieldClassStr);
    }

    public static String getterAndcast(String sourceFieldStr, String sourceFieldClassStr, String targetFieldClassStr) {
        if ("java.lang.String".equals(sourceFieldClassStr) && "java.lang.Integer".equals(targetFieldClassStr)) {
            return "new Integer(" + getter(sourceFieldStr) + ")";
        }
        if ("java.lang.Integer".equals(sourceFieldClassStr) && "java.lang.String".equals(targetFieldClassStr)) {
            return getter(sourceFieldStr) + ".toString()";
        }
        return getter(sourceFieldStr);
    }

    private static String getter(String sourceFieldStr) {
        return "source.get" + capitalizeFirstLetter(sourceFieldStr) + "()";
    }

    private static String capitalizeFirstLetter(String input) {
        if (input == null || input.isEmpty()) {
            return input; // 如果字符串为空或null，直接返回
        }
        // 获取首字母并转换为大写
        char firstChar = Character.toUpperCase(input.charAt(0));
        // 获取剩余的子字符串
        String restOfString = input.substring(1);
        // 拼接首字母和剩余的子字符串
        return firstChar + restOfString;
    }

//    private static void makeReadOnly(String filePath) throws Exception {
//        File file = new File(filePath);
//        if (!file.exists()) {
//            throw new IllegalArgumentException("File does not exist: " + filePath);
//        }
//
//        // 检测操作系统类型
//        String os = System.getProperty("os.name").toLowerCase();
//
//        if (os.contains("win")) {
//            // Windows 系统：使用文件属性
//            setReadOnlyOnWindows(file);
//        } else {
//            // 类 Unix 系统：使用 POSIX 权限
//            setReadOnlyOnUnix(file);
//        }
//    }
//
//    private static void setReadOnlyOnUnix(File file) throws Exception {
//        // 使用 POSIX 文件权限
//        Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file.toPath());
//        perms.remove(PosixFilePermission.OWNER_WRITE);
//        perms.remove(PosixFilePermission.GROUP_WRITE);
//        perms.remove(PosixFilePermission.OTHERS_WRITE);
//        Files.setPosixFilePermissions(file.toPath(), perms);
//    }
//
//    private static void setReadOnlyOnWindows(File file) {
//        // 使用 Windows 文件属性
//        boolean success = file.setReadOnly();
//        if (!success) {
//            throw new IllegalStateException("Failed to set file as read-only on Windows: " + file.getAbsolutePath());
//        }
//    }
//
//    private static void cancelReadOnly(String filePath) throws Exception {
//        File file = new File(filePath);
//        if (!file.exists()) {
//            throw new IllegalArgumentException("File does not exist: " + filePath);
//        }
//
//        // 检测操作系统类型
//        String os = System.getProperty("os.name").toLowerCase();
//
//        if (os.contains("win")) {
//            // Windows 系统：使用文件属性
//            cancelReadOnlyOnWindows(file);
//        } else {
//            // 类 Unix 系统：使用 POSIX 权限
//            cancelReadOnlyOnUnix(file);
//        }
//    }
//
//    private static void cancelReadOnlyOnUnix(File file) throws Exception {
//        // 使用 POSIX 文件权限
//        Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file.toPath());
//        perms.add(PosixFilePermission.OWNER_WRITE);
//        perms.add(PosixFilePermission.GROUP_WRITE);
//        perms.add(PosixFilePermission.OTHERS_WRITE);
//        Files.setPosixFilePermissions(file.toPath(), perms);
//    }
//
//    private static void cancelReadOnlyOnWindows(File file) {
//        // 使用 Windows 文件属性
//        boolean success = file.setWritable(true);
//        if (!success) {
//            throw new IllegalStateException("Failed to cancel file read-only on Windows: " + file.getAbsolutePath());
//        }
//    }
}
